/*
                    CursorEngine Class Implementation
*/
#include "CursorEngine.h"

Point CursorEngine::Position = Point(0, 0);
vector<Cursor*> CursorEngine::Cursors = vector<Cursor*>();
string CursorEngine::strActiveCursor = "";
bool CursorEngine::bActiveCursor = false;
bool CursorEngine::bWasOutside = false;
bool CursorEngine::bMouseDown = false;
SDL_Surface* CursorEngine::DraggingImage = NULL;
Point CursorEngine::DraggingOffset = Point(0, 0);
vector<string> CursorEngine::strDraggingData = vector<string>();
vector<MouseContextMenu*> CursorEngine::ContextMenus = vector<MouseContextMenu*>();
MouseContextMenu* CursorEngine::currentContextMenu = NULL;
bool CursorEngine::bDragging = false;
bool CursorEngine::bContextMenuOpened = false;
Label CursorEngine::lblTooltip = Label();
bool CursorEngine::bShowTooltip = false;

void CursorEngine::FreeCursors()
{
    for (vector<Cursor*>::iterator iter = Cursors.begin(); iter != Cursors.end(); iter++)
    {
        delete *iter;
    }

    Cursors.clear();

    strDraggingData.clear();

    SDL_FreeSurface(DraggingImage);

    SDL_ShowCursor(SDL_ENABLE);

    for (int i = 0; i < ContextMenus.size(); i++)
    {
        delete ContextMenus.at(i);
    }

    ContextMenus.clear();

    currentContextMenu = NULL;
}

int CursorEngine::Initialise()
{
    int nx, ny;

    SDL_GetMouseState(&nx, &ny);

    Position = Point(nx, ny);

    lblTooltip.Initialise(Point(0, -20), "Data//Fonts//gui.ttf", 18, "", GetSDLColor(0, 0, 0));
}

int CursorEngine::AddCursor(const string& strNewName, const string& strFilepath, const Point& Focus, const string& strFilepath_c)
{
    Cursor *temp = new Cursor;

    if (temp == NULL)
    {
        #ifdef DEBUG
            printf("CursorEngine Create Error: Null temp pointer");
        #endif

        return -1;
    }

    if (temp->setImage(strFilepath) == -1)
    {
        delete temp;

        return -1;
    }

    temp->setFocus(Focus);
    temp->setName(strNewName);

    if (temp->setImage_C(strFilepath_c) == -1)
    {
        temp->setImage_C(temp->getImage());
    }

    Cursors.push_back(temp);

    return 0;
}

int CursorEngine::SetActiveCursor(const string& strName)
{
    if (strName == "")
    {
        SDL_ShowCursor(SDL_ENABLE);

        bActiveCursor = false;

        strActiveCursor = strName;

        return 0;
    }

    if (GetCursorByName(strName) == -1)
    {
        printf("CursorEngine Set Cursor Error: Invalid Active Cursor Name");

        bActiveCursor = false;

        SDL_ShowCursor(SDL_ENABLE);

        return -1;
    }
    else
    {
        strActiveCursor = strName;

        bActiveCursor = true;

        SDL_ShowCursor(SDL_DISABLE);

        return 0;
    }
}

int CursorEngine::HandleMouseMotion(const int& iMouseXREL, const int& iMouseYREL)
{
    int nx, ny;

    SDL_GetMouseState(&nx, &ny);

    Position = Point(nx, ny);

    return 0;
}

void CursorEngine::AddContextMenu(const string& strName, const vector<string>& Items)
{
    ContextMenus.push_back(new MouseContextMenu);

    ContextMenus.back()->Initialise(strName, Items, 18, GetSDLColor(255, 255, 255), GetSDLColor(47, 99, 191), 15, 15, 5,
                                    "Data//Images//ContextMenu//header.png",
                                    "Data//Images//ContextMenu//footer.png",
                                    "Data//Images//ContextMenu//back.png");
}

void CursorEngine::OpenContextMenu(const string& strName, const string& strMenuData)
{
    if (currentContextMenu != NULL)
    {
        currentContextMenu->CloseMenu();
        delete currentContextMenu;
        currentContextMenu = NULL;

        bContextMenuOpened = false;
    }

    for (int i = 0; i < ContextMenus.size(); i++)
    {
        if (ContextMenus.at(i)->getName() == strName)
        {
            currentContextMenu = ContextMenus.at(i);

            int nx, ny;
            SDL_GetMouseState(&nx, &ny);
            currentContextMenu->OpenMenu(Point(nx, ny), strMenuData);

            bContextMenuOpened = true;

            return;
        }
    }
}

int CursorEngine::BlitToScreen(SDL_Surface *screen)
{
    // Check if the mouse is inside the window
    if (SDL_GetAppState() & SDL_APPMOUSEFOCUS)
    {
        if (bWasOutside == true)
        {
            bWasOutside = false;

            bActiveCursor = true;

            SDL_ShowCursor(SDL_DISABLE);
        }
    }
    else
    {
        if (bWasOutside == false)
        {
            bActiveCursor = false;

            bWasOutside = true;

            SDL_ShowCursor(SDL_ENABLE);
        }
    }

    if (bDragging == true)
    {
        if (DraggingImage != NULL)
        {
            SDL_Rect dest;

            dest.x = static_cast<int>(Position.x) - static_cast<int>(DraggingOffset.x);
            dest.y = static_cast<int>(Position.y) - static_cast<int>(DraggingOffset.y);

            SDL_BlitSurface(DraggingImage, NULL, screen, &dest);
        }
    }

    if (currentContextMenu != NULL)
    {
        currentContextMenu->BlitToSurface(screen);
    }

    if (bActiveCursor == false)
    {
        return -1;
    }
    else
    {
        int i = GetCursorByName(strActiveCursor);

        if (i == -1)
        {
            return -1;
        }

        double nx, ny;

        nx = Position.x - Cursors.at(i)->getFocus().x;
        ny = Position.y - Cursors.at(i)->getFocus().y;

        SDL_Rect dest;
        dest.x = static_cast<int>(nx);
        dest.y = static_cast<int>(ny);

        if (bMouseDown == false)
        {
            SDL_BlitSurface(Cursors.at(i)->getImage(), NULL, screen, &dest);
        }
        else
        {
            SDL_BlitSurface(Cursors.at(i)->getImage_C(), NULL, screen, &dest);
        }

        if (bShowTooltip == true)
        {
            lblTooltip.BlitToFrame(screen, Position);
        }

        return 0;
    }
}

int CursorEngine::MoveRelative(const double& nx, const double& ny)
{
    Position.x += nx;
    Position.y += ny;

    return 0;
}

int CursorEngine::GetCursorByName(const string& strName)
{
    int i = 0;

    for (vector<Cursor*>::iterator iter = Cursors.begin(); iter != Cursors.end(); iter++)
    {
        if ((*iter)->getName() == strName)
        {
            return i;
        }

        i++;
    }

    // If no cursor is found then return -1
    return -1;
}

void CursorEngine::setPosition(const Point& NewPosition)
{
    Position = NewPosition;
}

void CursorEngine::setPosition(const double& nx, const double& ny)
{
    Position.x = nx;
    Position.y = ny;
}

Point CursorEngine::getPosition()
{
    return Position;
}

int CursorEngine::parseInput(const SDL_Event& event)
{
    switch (event.type)
    {
        case SDL_MOUSEMOTION:

            HandleMouseMotion(event.motion.xrel, event.motion.yrel);

            if (currentContextMenu != NULL)
            {
                currentContextMenu->HandleMouseMotion(event.motion.xrel, event.motion.yrel);
            }

        break;

        case SDL_MOUSEBUTTONDOWN:

            if (event.button.button == SDL_BUTTON_LEFT)
            {
                bMouseDown = true;
            }
            else
            {
                bMouseDown = true;
            }

        break;

        case SDL_MOUSEBUTTONUP:

            if (event.button.button == SDL_BUTTON_LEFT)
            {
                bMouseDown = false;
                bDragging = false;

                if (currentContextMenu != NULL && bContextMenuOpened == false)
                {
                    string strSelectedItem = currentContextMenu->HandleMouseUp(event.button.x, event.button.y);

                    if (strSelectedItem != "")
                    {
                        HandleContextMenuClick(currentContextMenu->getName(), strSelectedItem, currentContextMenu->getTargetData());
                    }

                    currentContextMenu->CloseMenu();

                    currentContextMenu = NULL;
                }
            }
            else
            {
                bMouseDown = false;
                bDragging = false;

                if (currentContextMenu != NULL && bContextMenuOpened == false)
                {
                    currentContextMenu->CloseMenu();

                    currentContextMenu = NULL;
                }
            }

        break;
    }

    bContextMenuOpened = false;

    return 0;
}

void CursorEngine::HandleContextMenuClick(const string& strName, const string& strSelected, const string& strMenuData)
{

}

void CursorEngine::StartDragging(SDL_Surface* NewDraggingImage, vector<string> strNewDraggingData, Point NewDraggingOffset)
{
    strDraggingData.clear();

    DraggingImage = NewDraggingImage;

    strDraggingData = strNewDraggingData;

    DraggingOffset = NewDraggingOffset;

    bDragging = true;
}

void CursorEngine::ClearDraggingData()
{
    DraggingImage = NULL;

    strDraggingData.clear();

    DraggingOffset = Point(0, 0);
}

void CursorEngine::StopDragging()
{
    bDragging = false;
}

SDL_Surface* CursorEngine::getDraggingImage()
{
    return DraggingImage;
}

vector<string>& CursorEngine::getDraggingData()
{
    return strDraggingData;
}

Point CursorEngine::getDraggingOffset()
{
    return DraggingOffset;
}

void CursorEngine::ShowTooltip(const string& strTooltip)
{
    lblTooltip.setText(strTooltip);

    bShowTooltip = true;
}

void CursorEngine::HideTooltip()
{
    bShowTooltip = false;
}
